// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © TheUltimator5

//@version=6
strategy("Strategy Chameleon [theUltimator5]", 
         shorttitle="Chameleon", 
         overlay=true, 
         default_qty_type=strategy.percent_of_equity, 
         default_qty_value=10,
         calc_on_every_tick=false,
         pyramiding=1)

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════
// INPUTS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════

// External Signal Sources
buySignal = input.source(close, "Buy Signal Source", 
     tooltip="Connect this to any external indicator's buy signal. The indicator should output a value > 0 when buy condition is met.",
     group="Signal Sources")
    
sellSignal = input.source(close, "Sell Signal Source", 
     tooltip="Connect this to any external indicator's sell signal. The indicator should output a value > 0 when sell condition is met.",
     group="Signal Sources")

// Display Settings
tablePosition = input.string("Bottom Right", "Table Position", 
     options=["Top Left", "Top Center", "Top Right", "Middle Left", "Middle Center", "Middle Right", "Bottom Left", "Bottom Center", "Bottom Right"],
     group="Display Settings")
showTable = input.bool(true, "Show Performance Table", group="Display Settings")

// Trading Direction
tradeDirection = input.string("Both", "Trade Direction", 
     options=["Long Only", "Short Only", "Both"],
     group="Trading Rules")

// Risk Management
useStopLoss = input.bool(true, "Use Stop Loss", group="Risk Management")
stopLossType = input.string("Percentage", "Stop Loss Type", 
     options=["Percentage", "ATR", "Fixed Points"],
     group="Risk Management")
    
stopLossPercent = input.float(2.0, "Stop Loss %", minval=0.1, maxval=50.0, group="Risk Management")
stopLossATR = input.float(2.0, "Stop Loss ATR Multiplier", minval=0.1, maxval=10.0, group="Risk Management")
stopLossPoints = input.float(100, "Stop Loss Points", minval=1, group="Risk Management")
atrLength = input.int(14, "ATR Length", minval=1, group="Risk Management")

// Trailing Stop
useTrailingStop = input.bool(true, "Use Trailing Stop", group="Trailing Stop")
trailType = input.string("Percentage", "Trailing Stop Type", 
     options=["Percentage", "ATR", "Fixed Points"],
     group="Trailing Stop")
    
trailPercent = input.float(1.5, "Trailing Stop %", minval=0.1, maxval=50.0, group="Trailing Stop")
trailATR = input.float(1.5, "Trailing Stop ATR Multiplier", minval=0.1, maxval=10.0, group="Trailing Stop")
trailPoints = input.float(50, "Trailing Stop Points", minval=1, group="Trailing Stop")

// Take Profit
useTakeProfit = input.bool(false, "Use Take Profit", group="Take Profit")
takeProfitType = input.string("Risk:Reward", "Take Profit Type", 
     options=["Risk:Reward", "Percentage", "ATR", "Fixed Points"],
     group="Take Profit")
    
riskRewardRatio = input.float(2.0, "Risk:Reward Ratio", minval=0.1, maxval=10.0, group="Take Profit")
takeProfitPercent = input.float(4.0, "Take Profit %", minval=0.1, maxval=100.0, group="Take Profit")
takeProfitATR = input.float(3.0, "Take Profit ATR Multiplier", minval=0.1, maxval=20.0, group="Take Profit")
takeProfitPoints = input.float(200, "Take Profit Points", minval=1, group="Take Profit")



// Time Filter
useTimeFilter = input.bool(false, "Use Time Filter", group="Time Filter")
startTime = input.session("0930-1600", "Trading Session", group="Time Filter")

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════
// HELPER FUNCTIONS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Get table position
getTablePosition() =>
    switch tablePosition
        "Top Left" => position.top_left
        "Top Center" => position.top_center
        "Top Right" => position.top_right
        "Middle Left" => position.middle_left
        "Middle Center" => position.middle_center
        "Middle Right" => position.middle_right
        "Bottom Left" => position.bottom_left
        "Bottom Center" => position.bottom_center
        "Bottom Right" => position.bottom_right
        => position.top_right

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════
// CALCULATIONS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════

// ATR for dynamic stops
atr = ta.atr(atrLength)

// Time filter
inSession = not useTimeFilter or not na(time(timeframe.period, startTime))

// Signal Detection Functions
getBuySignal() =>
    buySignal > 0 and buySignal[1] == 0

getSellSignal() =>
    sellSignal > 0 and sellSignal[1] == 0

// Entry Conditions
longCondition = getBuySignal() and inSession and (tradeDirection == "Long Only" or tradeDirection == "Both")
shortCondition = getSellSignal() and inSession and (tradeDirection == "Short Only" or tradeDirection == "Both")

// Stop Loss Calculation
getStopLoss(isLong, entryPrice) =>
    if useStopLoss
        switch stopLossType
            "Percentage" => isLong ? entryPrice * (1 - stopLossPercent/100) : entryPrice * (1 + stopLossPercent/100)
            "ATR" => isLong ? entryPrice - (atr * stopLossATR) : entryPrice + (atr * stopLossATR)
            "Fixed Points" => isLong ? entryPrice - stopLossPoints : entryPrice + stopLossPoints
            => na
    else
        na

// Take Profit Calculation
getTakeProfit(isLong, entryPrice, stopPrice) =>
    if useTakeProfit
        switch takeProfitType
            "Risk:Reward" => 
                if not na(stopPrice)
                    riskAmount = math.abs(entryPrice - stopPrice)
                    isLong ? entryPrice + (riskAmount * riskRewardRatio) : entryPrice - (riskAmount * riskRewardRatio)
                else
                    na
            "Percentage" => isLong ? entryPrice * (1 + takeProfitPercent/100) : entryPrice * (1 - takeProfitPercent/100)
            "ATR" => isLong ? entryPrice + (atr * takeProfitATR) : entryPrice - (atr * takeProfitATR)
            "Fixed Points" => isLong ? entryPrice + takeProfitPoints : entryPrice - takeProfitPoints
            => na
    else
        na

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════
// STRATEGY LOGIC
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Entry Orders
if longCondition and strategy.position_size == 0
    entryPrice = close
    stopPrice = getStopLoss(true, entryPrice)
    limitPrice = getTakeProfit(true, entryPrice, stopPrice)
    
    strategy.entry("Long", strategy.long)
    
    if not na(stopPrice)
        strategy.exit("Long Exit", "Long", stop=stopPrice, limit=limitPrice)
    else if not na(limitPrice)
        strategy.exit("Long Exit", "Long", limit=limitPrice)

if shortCondition and strategy.position_size == 0
    entryPrice = close
    stopPrice = getStopLoss(false, entryPrice)
    limitPrice = getTakeProfit(false, entryPrice, stopPrice)
    
    strategy.entry("Short", strategy.short)
    
    if not na(stopPrice)
        strategy.exit("Short Exit", "Short", stop=stopPrice, limit=limitPrice)
    else if not na(limitPrice)
        strategy.exit("Short Exit", "Short", limit=limitPrice)

// Trailing Stop Logic
var float longTrailStop = na
var float shortTrailStop = na

if strategy.position_size > 0 and useTrailingStop
    trailDistance = switch trailType
        "Percentage" => close * (trailPercent/100)
        "ATR" => atr * trailATR
        "Fixed Points" => trailPoints
        => close * 0.02
    
    newTrailStop = close - trailDistance
    longTrailStop := na(longTrailStop) ? newTrailStop : math.max(longTrailStop, newTrailStop)
    
    if close <= longTrailStop
        strategy.close("Long", comment="Trail Stop")
        longTrailStop := na

if strategy.position_size < 0 and useTrailingStop
    trailDistance = switch trailType
        "Percentage" => close * (trailPercent/100)
        "ATR" => atr * trailATR
        "Fixed Points" => trailPoints
        => close * 0.02
    
    newTrailStop = close + trailDistance
    shortTrailStop := na(shortTrailStop) ? newTrailStop : math.min(shortTrailStop, newTrailStop)
    
    if close >= shortTrailStop
        strategy.close("Short", comment="Trail Stop")
        shortTrailStop := na

// Reset trailing stops when no position
if strategy.position_size == 0
    longTrailStop := na
    shortTrailStop := na

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════
// PLOTTING
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════

// Plot buy/sell signals for debugging
plotshape(longCondition, "Buy Signal", shape.triangleup, location.belowbar, color.green, size=size.small)
plotshape(shortCondition, "Sell Signal", shape.triangledown, location.abovebar, color.red, size=size.small)

// Plot trailing stops
plot(strategy.position_size > 0 ? longTrailStop : na, "Long Trail Stop", color.red, linewidth=2, style=plot.style_linebr)
plot(strategy.position_size < 0 ? shortTrailStop : na, "Short Trail Stop", color.red, linewidth=2, style=plot.style_linebr)

// Plot signal sources for debugging (scaled to fit chart)
hline(0, "Zero Line", color.gray, linestyle=hline.style_dashed)

// Background color for active session
bgcolor(inSession and useTimeFilter ? color.new(color.blue, 95) : na, title="Trading Session")

// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════
// ALERTS
// ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════

alertcondition(longCondition, "Long Entry Alert", "External Signal Strategy: Long Entry Triggered")
alertcondition(shortCondition, "Short Entry Alert", "External Signal Strategy: Short Entry Triggered")

// Custom Performance Table
if barstate.islast and showTable
    var table perfTable = table.new(getTablePosition(), 3, 6, bgcolor=color.white, border_width=1)
    
    // Header row
    table.cell(perfTable, 0, 0, "PERFORMANCE", text_color=color.white, bgcolor=color.gray, text_size=size.small)
    table.cell(perfTable, 1, 0, "COUNT", text_color=color.white, bgcolor=color.gray, text_size=size.small)
    table.cell(perfTable, 2, 0, "PERCENTAGE", text_color=color.white, bgcolor=color.gray, text_size=size.small)
    
    // Calculate trade statistics
    totalTrades = strategy.closedtrades
    winningTrades = strategy.wintrades
    losingTrades = strategy.losstrades
    
    winPercentage = totalTrades > 0 ? (winningTrades / totalTrades * 100) : 0
    lossPercentage = totalTrades > 0 ? (losingTrades / totalTrades * 100) : 0
    netProfitPercent = strategy.initial_capital > 0 ? (strategy.netprofit / strategy.initial_capital * 100) : 0
    
    // Total Trades
    table.cell(perfTable, 0, 1, "Total Trades", text_color=color.black, text_size=size.small)
    table.cell(perfTable, 1, 1, str.tostring(totalTrades), text_color=color.black, text_size=size.small)
    table.cell(perfTable, 2, 1, "100%", text_color=color.black, text_size=size.small)
    
    // Winning Trades
    table.cell(perfTable, 0, 2, "Winning Trades", text_color=color.black, text_size=size.small)
    table.cell(perfTable, 1, 2, str.tostring(winningTrades), text_color=color.green, text_size=size.small)
    table.cell(perfTable, 2, 2, str.tostring(winPercentage, "#.#") + "%", text_color=color.green, text_size=size.small)
    
    // Losing Trades
    table.cell(perfTable, 0, 3, "Losing Trades", text_color=color.black, text_size=size.small)
    table.cell(perfTable, 1, 3, str.tostring(losingTrades), text_color=color.red, text_size=size.small)
    table.cell(perfTable, 2, 3, str.tostring(lossPercentage, "#.#") + "%", text_color=color.red, text_size=size.small)
    
    // Net Profit
    table.cell(perfTable, 0, 4, "Net Profit", text_color=color.black, text_size=size.small)
    table.cell(perfTable, 1, 4, str.tostring(strategy.netprofit, "#.##"), text_color=strategy.netprofit > 0 ? color.green : color.red, text_size=size.small)
    table.cell(perfTable, 2, 4, str.tostring(netProfitPercent, "#.#") + "%", text_color=strategy.netprofit > 0 ? color.green : color.red, text_size=size.small)
    
    // Trailing Stop
    table.cell(perfTable, 0, 5, "Trail Stop", text_color=color.black, text_size=size.small)
    trailPercentDisplay = trailType == "Percentage" ? str.tostring(trailPercent, "#.#") + "%" : 
                         trailType == "ATR" ? str.tostring(trailATR, "#.#") + "x ATR" : 
                         str.tostring(trailPoints) + " pts"
    table.cell(perfTable, 1, 5, trailPercentDisplay, text_color=color.black, text_size=size.small)
    table.cell(perfTable, 2, 5, useTrailingStop ? "ENABLED" : "DISABLED", 
               text_color=useTrailingStop ? color.green : color.gray, text_size=size.small)
